/**
 * 
 */
package ictius.estructuras.implement;

import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * @author tadeo
 *
 */
/**
 * @author tadeo
 *
 */
public final class ListaEnlazada extends AbstractCollection<Object> {

    private Nodo inicioMarca;
    private Nodo finMarca;
    private int elTamaño;
 //   private int modCont = 0;
    private static final Nodo NOT_FOUND = null;

    public ListaEnlazada() {
        vaciar();
    }

    public ListaEnlazada(Collection<Object> otro) {
        vaciar();
        Iterator<Object> itr = otro.iterator();
        while (itr.hasNext()) {
            add(itr.next());
        }
    }

    /**
     * Vuelve a cero el contador y pone el nodo inicial al lado del nodo del último.
     */
    public void vaciar() {
        inicioMarca = new Nodo("BEGINMARKER", null, null);
        finMarca = new Nodo("ENDMARKER", inicioMarca, null);
        inicioMarca.siguiente = finMarca;

        elTamaño = 0;
    //    modCont++;
    }

    /**
     * Devuelve el tamaño (cantidad de elemento) de la colección.
     * @return Devuelve el tamaño (cantidad de elemento) de la colección.
     */
    @Override
    public int size() {
        return elTamaño;
    }

    /**
     * Prueba si está en la colección el item consultado
     * @param x que es un objeto cualqueira.
     * @return verdadero si existe el elemento <i>x</i> o falso sino existe. 
     */
    public boolean contiene(Object x) {
        return buscaPosi(x) != NOT_FOUND; //findPos
    }

    /**
     * @param x que es un objeto cualqueira.
     * @return la posición del primer elemento que coíncida con x en la colección, 
     * o NOT_FOUND  si no se encuentra.
     */
    public Nodo buscaPosi(Object x) {
        for (Nodo p = inicioMarca.siguiente; p != finMarca; p = p.siguiente) {
            if (x == null) {
                if (p.dato == null) {
                    return p;
                }
            } else if (x.equals(p.dato)) {
                return p;
            }
        }

        return NOT_FOUND;
    }

    /**
     * Agregar un item a la colección en una posición específica.
     * Items antes o después de esa posición  son desplaza hacía arriba.
     * @parama x es cualqueir objeto.
     * @param idx es la posición donde debe ser insertado x. 
     * @throws IndexOutOfBoundsException si idx no está entre 0 y tamaño(), inclusive.
     */
    public void insertar(int idx, Object x) {
    	System.out.println("Insertado en " + idx + " el objeto " + x.toString());
        Nodo p = getNodo(idx);
        Nodo newNodo = new Nodo(x, p.previo, p);
        newNodo.previo.siguiente = newNodo;
        p.siguiente = newNodo;
        elTamaño++;
    //    modCont++;
    }

    /**
     * Inserta en la colección el elemento <i>x</i>, al principio.
     * Otros items son desplazados una posición más arriba.
     * @param x es cualquier objeto.
     */
   /* public void insertarPrimero(Object x) {
        insertar(0, x);
    }*/

    /**
     * Agrega el item <i>x</i> al final de la colección.
     * @param x es cualqueir objeto.
     */
 /*   public void insertarFinal(Object x) {
        insertar(size(), x);
    }*/

    /**
     * Regresa con el primer elemento de la lista.
     * @return regresa con el primer elemento de la lista.
     * @throws NoSuchElementException si la lista está vacía.
     */
    
    public Object getPrimero() {
        if (esVacia()) {
            throw new NoSuchElementException();
        }
        return getNodo(0).dato;
    }

    /**
     * Obtiene el Nodo a determinada posición, el cual debe estar en el rango de 0 a <i>size()</i>.
     * @param idx indice de donde se encuentra el elemento buscado.
     * @return nodo interno que responde a la dirección dada por idx.
     * @throws IndexOutOfBoundsException si idx no está en el rango de 0 a <i>size()</i>.
     */
    private Nodo getNodo(int idx) {
        Nodo p;
        if (idx < 0 || idx > size()) {
            throw new IndexOutOfBoundsException("getNodo index: " + idx + "; tamaño: " + size());
        }
        if (idx < size() / 2) {
            p = inicioMarca.siguiente;
            for (int i = 0; i < idx; i++) {
                p = p.siguiente;
            }
        } else {
            p = finMarca;
            for (int i = size(); i > idx; i--) {
                p = p.previo;
            }
        }

        return p;
    }

    public boolean esVacia() {
        return elTamaño == 0;
    }
    
    public Object buscar(Object elemento){
    	System.out.println("Elemento buscado " + elemento.toString());
    	//Nodo p = inicioMarca.siguiente; p != finMarca; p = p.siguiente
    	for (Nodo p = inicioMarca.siguiente; p != finMarca; p = p.siguiente) {
    		System.out.println(p.dato.toString());
    	}
    	return null;
    }

  /*  public void insert(Object x){
    	Nodo temp = new Nodo(x);
    	temp = inicioMarca;
    	
    	while(inicioMarca.siguiente != null){
    		inicioMarca = inicioMarca.siguiente;
    	}
    	
    	finMarca.siguiente;
    }
	/* (non-Javadoc)
	 * @see java.util.AbstractCollection#iterator()
	 */
	@Override
	public Iterator<Object> iterator() {
		// TODO Auto-generated method stub
		return null;
	}

}
